Skip to content

steinarb/servlet

Repository files navigation

Java servlet common code

Servlet and filter classes that are intended to be inherited to cut down on boilerplate code

Status of the project

https://github.com/steinarb/servlet/actions/workflows/servlet-maven-ci-build.yml/badge.svg https://coveralls.io/repos/github/steinarb/servlet/badge.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=alert_status#.svg https://maven-badges.herokuapp.com/maven-central/no.priv.bang.servlet/servlet/badge.svg https://www.javadoc.io/badge/no.priv.bang.servlet/servlet.svg

https://sonarcloud.io/images/project_badges/sonarcloud-white.svg

https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=sqale_index#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=coverage#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=ncloc#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=code_smells#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=sqale_rating#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=security_rating#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=bugs#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=vulnerabilities#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=duplicated_lines_density#.svg https://sonarcloud.io/api/project_badges/measure?project=steinarb_servlet&metric=reliability_rating#.svg

Release history

DateVersionComment
<2024-03-25 Mon 12:36>1.6.11jersey 2.42, jackson 2.16.2
<2024-03-01 Fri 17:54>1.6.10add shiro-jaxrs feature to JerseyServlet
<2023-11-05 Sun 10:37>1.6.9jersey 2.41, jackson 2.15.3, junit jupiter 5.10.0, mockito 5.7.0, and mockrunner 2.0.7
<2023-07-30 Sun 14:03>1.6.8Use jersey-karaf-feature 1.9.6, jersey 2.40 and jackson 2.15.2, built with Java 17
<2023-04-26 Wed 00:12>1.6.7Use jersey-karaf-feature 1.9.5 and jackson 2.15.0
<2023-04-24 Mon 19:16>1.6.6Use jersey-karaf-feature 1.9.4, jersey 2.39.1 and jackson 2.14.2
<2023-04-14 Fri 17:08>1.6.5Set cache-control and expires headers to avoid index.html caching of webapps
<2023-01-14 Sat 12:47>1.6.4Add overridable method for reporting not found errors to FrontendServlet
<2022-11-28 Mon 21:33>1.6.3Use jersey 2.37. Use jackson 2.14.1 to fix CVE-2022-42003 and CVE-2022-42004
<2022-08-10 Wed 21:34>1.6.2Use jersey 2.36, karaf 4.4.1, maven-bundle-plugin 5.1.8
<2022-06-01 Wed 16:57>1.6.1Use jackson 2.13.3
<2022-05-29 Sun 09:11>1.6.0Use karaf 4.4.0 and OSGi 8
<2022-02-20 Sun 00:03>1.5.8Use jersey 2.35 and jackson 2.13.1
<2021-06-15 Tue 22:22>1.5.7Use jersey 2.34 and jackson 2.12.3
<2021-06-09 Wed 00:27>1.5.6Avoid inherited imported dependencies leaking out in the servlet BoM
<2021-06-01 Tue 00:07>1.5.5Use karaf 4.3.2 and the osgi.cmpn maven dependency of OSGi 7 compendium
<2021-05-02 Sun 17:34>1.5.4Use a jersey feature version that supports java.time serialization/deserialization
<2021-04-19 Mon 01:00>1.5.3Use the OSGi adapters BoM
<2021-04-17 Sat 21:34>1.5.2Provide maven Bill of Materials to simplify usage
<2021-04-15 Thu 20:40>1.5.1Get maven dependencies and maven plugin config from a parent POM
<2021-04-12 Mon 18:10>1.5.0Built with karaf 4.3.0 and OSGi 7
<2021-01-24 Sun 21:25>1.4.0Use jersey 2.33 and jackson 2.12.1
<2020-09-12 Sat 16:30>1.3.2Fix issue #3 by requiring package from jersey-inject-hk2
<2020-09-11 Fri 22:25>1.3.1Does not pull in servicemix javax.inject at runtime
<2020-07-31 Fri 13:07>1.3.0Fix issue #2 in FrontendServlet, add content-type for .ico files
<2020-07-29 Wed 16:12>1.2.0Fix issue #1 in FrontendServlet
<2020-04-09 Thu 22:40>1.1.3Compile and runtime dependencies to jersey 2.30.1, runtime dependencies to jackson 2.10.3
<2020-03-05 Thu 18:22>1.1.2Use runtime dependency to jackson-databind 2.9.10.3 to fix security issue CVE-2020-8840
<2020-02-21 Fri 22:42>1.1.1Bugfix release of the JerseyServlet with correct method name
<2020-02-19 Wed 07:52>1.1.0First release of the JerseyServlet
<2020-01-12 Sun 23:26>1.0.0First release of the FrontendServlet

Overview of the project

Frontend

This is a servlet that’s intended to be extended by a servlet serving out a JS frontend packed by webpack.

The servlet will search for resources matching the pathInfo (minus the webcontext) on the classpath and serve them out, setting the content type based on the file name extension.

The servlet will try serving the file “index.html” (that must exist on the classpath) for a list of routes, that can be set by a subclass. This is to handle reloads of URLs set by e.g. the react router.

To use the servlet in an application built with maven, add the maven dependency:

<dependency>
 <groupId>no.priv.bang.servlet</groupId>
 <artifactId>servlet.frontend</artifactId>
 <version>1.6.11</version>
</dependency>

To use the servlet in a webapp running in the apache karaf web whiteboard apache:

  1. Import the Bill of Materials (BoM) into the project’s dependencyManagement
    <build>
     <dependencyManagement>
      <dependencies>
       <dependency>
        <groupId>no.priv.bang.servlet</groupId>
        <artifactId>servlet-bom</artifactId>
        <version>1.6.11</version>
        <type>pom</type>
        <scope>import</scope>
       </dependency>
      </dependencies>
     </dependencyManagement>
    </build>
        
  2. Create a maven project building an OSGi bundle, and add the following maven dependencies to the project (the version of the dependencies, is provided by the BoM import)
    <build>
     <dependencies>
      <dependency>
       <groupId>no.priv.bang.servlet</groupId>
       <artifactId>servlet.frontend</artifactId>
       <scope>provided</scope>
      </dependency>
      <dependency>
       <groupId>no.priv.bang.servlet</groupId>
       <artifactId>servlet.frontend</artifactId>
       <type>xml</type>
       <classifier>features</classifier>
      </dependency>
     </dependencies>
    </build>
        

    The <provided> scope dependency provides compile time dependency for the bundle, and the xml classifier dependencies pulls the karaf runtime dependency of the sevlet into the feature for the OSGi bundle project

  3. In the OSGi bundle project, add a DS component registering with the web whiteboard
    @Component(service={Servlet.class}, property={"alias=/myapp"})
    public class ReactServlet extends FrontendServlet {
        public ReactServlet() {
            super();
            setRoutes("/", "/counter", "/about");
        }
    
        @Reference
        public void setLogservice(LogService logservice) {
            super.setLogService(logservice);
        }
    }
        

Processing content

In many cases, just sending resources found on the classpath, is what is wanted.

But in some cases it may be desirable to do processing on the resource found on the classpath, before it is returned.

One such example, is the “index.html” file that is used to boostrap the webapp returned by the FrontendServlet. In this case it is desirable to set Open Graph <meta> headers corresponding to the path the application is entered with.

This is so that you can give an URL to a specific subpage in a webapp, and that URL will return <meta> headers with information that will make the URL look nice in google searches and various social media.

To accomplish this, FrontendServlet has two overridable methods:

public class FrontendServlet extends HttpServlet{
    protected boolean thisIsAResourceThatShouldBeProcessed(String pathInfo, String resource, String contentType);
    protected void processResource(HttpServletResponse response, String pathInfo, String resource, String contentType) throws IOException;
}

The thisIsAResourceThatShouldBeProcessed() method is overridden to detect if a resource should be processed. If this method returns true, then processResource() will be called and no further handling of the request will be done by the FrontendServlet base class.

The FrontendServlet base implementation of processResource() returns the status code 501 Not Implemented.

Jersey

This is a servlet that’s intended to be extended by a servlet using jersey to implement a REST API.

The JerseyServlet does three things:

  1. Adds a way to add injected OSGi services to the HK2 dependency injection container, so that the OSGi services can be injected into Jersey resources, allowing the Jersey resources to be thin shims over OSGi service calls
  2. Adds the subpackage “.resources” of the servlet’s package as the default package to scan for Jersey resources Note! If a different package is set by configuration, this will override the default
  3. Adds the shiro-jaxrs ShiroFeature, which:
    1. configures exception mapping from Shiro’s AuthorizationException to HTTP status codes (401 and 403)
    2. exposes Shiro’s Subject as a java.security.Principal (Principal Propagation)
    3. Configures processing of Shiro’s annotations, which makes it easy to control access to JAX-RS resources by using annotations to require login, roles and permissions

To use the servlet in an application built with maven, add the maven dependency:

<dependency>
 <groupId>no.priv.bang.servlet</groupId>
 <artifactId>servlet.jersey</artifactId>
 <version>1.6.11</version>
</dependency>

To use the servlet in a webapp running in the apache karaf web whiteboard apache:

  1. Import the Bill of Materials (BoM) into the project’s dependencyManagement
    <build>
     <dependencyManagement>
      <dependencies>
       <dependency>
        <groupId>no.priv.bang.servlet</groupId>
        <artifactId>servlet-bom</artifactId>
        <version>1.6.11</version>
        <type>pom</type>
        <scope>import</scope>
       </dependency>
      </dependencies>
     </dependencyManagement>
    </build>
        
  2. Create a maven project building an OSGi bundle, and add the following maven dependencies to the project (the version of the dependencies, is provided by the BoM import)
    <build>
     <dependencies>
      <dependency>
       <groupId>no.priv.bang.servlet</groupId>
       <artifactId>servlet.jersey</artifactId>
       <scope>provided</scope>
      </dependency>
      <dependency>
       <groupId>no.priv.bang.servlet</groupId>
       <artifactId>servlet.jersey</artifactId>
       <type>pom</type>
       <scope>import</scope>
      </dependency>
     </dependencies>
    </build>
        

    The <provided> scope dependency provides compile time dependency for the bundle, and the xml classifier dependencies pulls the karaf runtime dependency of the sevlet into the feature for the OSGi bundle project

  3. In the OSGi bundle project, add a DS component registering with the web whiteboard.
    package no.priv.bang.servlet.jersey.test;
    
    @Component(service={Servlet.class})
    public class ExampleJerseyServlet extends JerseyServlet {
    
        @Reference
        public void setHelloService(HelloService service) {
            addInjectedOsgiService(HelloService.class, service);
        }
    
        @Reference
        public void setLogService(LogService logservice) {
            super.setLogService(logservice);
        }
    }
        

    Note! The OSGi LogService must be added by a separate method, since the LogService is used by the JerseyServlet itself (as well as being added to HK2, which makes it possible to use LogService in Jersey resources).

  4. Add resources implementing REST API endpoints in the .resources sub-package of the servlet’s package, and use @Inject to inject the OSGi services that JerseyServlet adds to the HK2 dependency injection container:
    package no.priv.bang.servlet.jersey.test.resources;
    
    @Path("/hello")
    public class HelloResource {
    
        @Inject
        HelloService service;
    
        @GET
        @Produces("text/plain")
        public String getHello() {
            return service.hello();
        }
    }
        

License

This code is licensed under the Apache license v. 2. See the LICENSE file for details.